package com.farm.bpm.server.impl;

import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.form.TaskFormData;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;

import com.farm.bpm.dao.FarmBpmDaoInter;
import com.farm.bpm.form.FarmActivitiFormParser;
import com.farm.bpm.form.Form;
import com.farm.bpm.server.FarmBpmServiceInter;
import com.farm.bpm.variable.VariableProvider;
import com.farm.core.auth.domain.LoginUser;
import com.farm.core.sql.query.DBRule;
import com.farm.core.sql.query.DBSort;
import com.farm.core.sql.query.DataQuery;
import com.farm.core.sql.result.DataResult;
import com.farm.doc.server.FarmDocManagerInter;

public class FarmBpmService implements FarmBpmServiceInter {
	private ProcessEngine processEngine;
	private FarmBpmDaoInter farmBpmDao;
	private FarmActivitiFormParser formParser;
	private FarmDocManagerInter docService;

	@Override
	public void deleteProcessInstance(String id, LoginUser currentUser) {
		farmBpmDao.setPROC_INST_ID_Null(id);
		processEngine.getRuntimeService().deleteProcessInstance(id,
				currentUser.getName() + "[" + currentUser.getId() + "]");

	}

	public FarmActivitiFormParser getFormParser() {
		return formParser;
	}

	public void setFormParser(FarmActivitiFormParser formParser) {
		this.formParser = formParser;
	}

	public FarmDocManagerInter getDocService() {
		return docService;
	}

	public void setDocService(FarmDocManagerInter docService) {
		this.docService = docService;
	}

	public ProcessEngine getProcessEngine() {
		return processEngine;
	}

	public void setProcessEngine(ProcessEngine processEngine) {
		this.processEngine = processEngine;
	}

	public FarmBpmDaoInter getFarmBpmDao() {
		return farmBpmDao;
	}

	public void setFarmBpmDao(FarmBpmDaoInter farmBpmDao) {
		this.farmBpmDao = farmBpmDao;
	}

	@Override
	public DataResult queryProcessInstanceQuery(DataQuery query)
			throws SQLException {
		DataQuery dbQuery = DataQuery
				.init(
						query,
						"act_ru_task c LEFT JOIN act_ru_execution a ON c.EXECUTION_ID_=a.ID_ LEFT JOIN act_re_procdef b ON a.PROC_DEF_ID_ = b.ID_ LEFT JOIN act_hi_procinst e ON e.PROC_INST_ID_=a.ID_",
						"a.ID_   AS id, b.VERSION_ AS VERSION,b.NAME_ AS procdefname, b.key_ AS procdefkey,b.ID_   AS procdefid,c.NAME_ AS taskname,c.ID_ AS taskid,e.START_TIME_ AS starttime,c.ASSIGNEE_ AS assignee,a.SUSPENSION_STATE_ AS active");
		DataResult result = dbQuery.search().runDictionary("1:活动,2:挂起",
				"ACTIVE");
		for (Map<String, Object> node : result.getResultList()) {
			node.put("TITLE", initProcessTitleDescription(node.get("ID")
					.toString(), node.get("PROCDEFID").toString()));
		}
		return result;
	}

	@Override
	public DataResult queryProcessDef(DataQuery query) throws SQLException {
		DataQuery dbQuery = DataQuery
				.init(
						query,
						"act_re_procdef",
						"ID_,REV_,CATEGORY_,NAME_,KEY_,VERSION_,DEPLOYMENT_ID_,RESOURCE_NAME_,DGRM_RESOURCE_NAME_,DESCRIPTION_,HAS_START_FORM_KEY_,SUSPENSION_STATE_,TENANT_ID_");

		DataResult result = dbQuery.search();
		result.runDictionary("1:激活,2:暂停", "SUSPENSION_STATE_");
		for (Map<String, Object> node : result.getResultList()) {
			node.put("NUM", processEngine.getRuntimeService()
					.createProcessInstanceQuery().processDefinitionId(
							node.get("ID_").toString()).count());
		}
		return result;
	}

	@Override
	public DataResult queryProcessStartIdentityLinks(DataQuery query,
			String processDefId) throws SQLException {
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		for (IdentityLink node : processEngine.getRepositoryService()
				.getIdentityLinksForProcessDefinition(processDefId)) {
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("USERID", node.getUserId());
			map.put("ID", node.getUserId());
			map.put("TASKID", node.getTaskId());
			map.put("TYPE", node.getType());
			map.put("GROUPID", node.getGroupId());
			list.add(map);
		}
		DataResult result = DataResult.getInstance(list, list.size(), 1, 100);
		return result;
	}

	@Override
	public void deployBpmn20XmlFile(InputStream inputStream, String fileName,
			String processType) {
		Deployment deply = processEngine.getRepositoryService()
				.createDeployment().addInputStream(fileName, inputStream)
				.deploy();
		for (ProcessDefinition pro : processEngine.getRepositoryService()
				.createProcessDefinitionQuery().deploymentId(deply.getId())
				.list()) {
			processEngine.getRepositoryService().setProcessDefinitionCategory(
					pro.getId(), processType);
		}
	}

	@Override
	public void deleteProcessDef(String processDefId) throws Exception {
		// 获取仓库服务对象
		RepositoryService repositoryService = processEngine
				.getRepositoryService();
		ProcessDefinition pd = repositoryService
				.getProcessDefinition(processDefId);
		long num = processEngine.getRuntimeService()
				.createProcessInstanceQuery().processDefinitionId(processDefId)
				.count();
		if (num > 0) {
			throw new Exception("该流程有" + num + "个实例在运行");
		}
		// 级联删除,会删除和当前规则相关的所有信息，包括历史
		repositoryService.deleteDeployment(pd.getDeploymentId(), true);
	}

	@Override
	public void activateProcessDefinitionById(String processDefId) {
		processEngine.getRepositoryService().activateProcessDefinitionById(
				processDefId);
	}

	@Override
	public void suspendProcessDefinitionById(String processDefId) {
		processEngine.getRepositoryService().suspendProcessDefinitionById(
				processDefId);

	}

	@Override
	public InputStream getBpmn20XmlFile(String processDefId) {
		return processEngine.getRepositoryService().getProcessModel(
				processDefId);
	}

	@Override
	public String getBpmn20XmlFileName(String processDefId) {
		return processEngine.getRepositoryService().getProcessDefinition(
				processDefId).getResourceName();
	}

	@Override
	public Map<String, Object> getBPMN20xmlUserGuideReport()
			throws SQLException {
		DataQuery query = DataQuery.getInstance("1", "NAME,ID",
				"alone_rolegroup");
		query.addRule(new DBRule("STATE", "1", "="));
		query.setPagesize(10000);
		DataResult result = query.search();
		DataQuery query2 = DataQuery
				.getInstance(
						"1",
						"a.NAME AS NAME,a.ID AS ID,c.NAME AS CNAME",
						"alone_user a LEFT JOIN alone_organization_user b ON a.ID=b.USERID LEFT JOIN alone_organization c ON c.ID=b.ORGANIZATIONID");
		query2.setPagesize(10000);
		query2.addRule(new DBRule("a.STATE", "1", "="));
		query2.addSort(new DBSort("c.NAME", "DESC"));
		DataResult result2 = query2.search();
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("forms", formParser.getPluginInfo());
		map.put("roles", result.getResultList());
		map.put("users", result2.getResultList());
		map.put("vars", VariableProvider.getAllVariableDescribe());
		return map;
	}

	@Override
	public InputStream getProcessDefDiagram(String processDefId) {
		return processEngine.getRepositoryService().getProcessDiagram(
				processDefId);
	}

	@Override
	public void addProcessStartRole(String processDefId, String roleid) {

		processEngine.getRepositoryService().addCandidateStarterGroup(
				processDefId, roleid);
	}

	@Override
	public void addProcessStartUser(String processDefId, String userid) {
		processEngine.getRepositoryService().addCandidateStarterUser(
				processDefId, userid);

	}

	@Override
	public void delStartUserOrRole(String processDefId, String roleidORuserid) {
		processEngine.getRepositoryService().deleteCandidateStarterGroup(
				processDefId, roleidORuserid);
		processEngine.getRepositoryService().deleteCandidateStarterUser(
				processDefId, roleidORuserid);

	}

	@Override
	public InputStream getProcessInstanceDiagram(String processInstanceId) {
		ProcessInstance proins = processEngine.getRuntimeService()
				.createProcessInstanceQuery().processInstanceId(
						processInstanceId).singleResult();
		BpmnModel model = processEngine.getRepositoryService().getBpmnModel(
				proins.getProcessDefinitionId());
		DefaultProcessDiagramGenerator pdg = new DefaultProcessDiagramGenerator();
		List<String> list = processEngine.getRuntimeService()
				.getActiveActivityIds(proins.getId());
		return pdg.generateDiagram(model, "PNG", list);
	}

	@Override
	public DataResult queryProcessInstanceVariables(DataQuery query,
			String processInstanceId) throws SQLException {
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		for (Entry<String, Object> node : processEngine.getRuntimeService()
				.getVariables(processInstanceId).entrySet()) {
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("KEY", node.getKey());
			map.put("VALUE", node.getValue());
			list.add(map);
		}
		DataResult result = DataResult.getInstance(list, list.size(), 1, 100);
		return result;
	}

	@Override
	public DataResult queryProcessInstanceIdentityLinks(DataQuery query,
			String processInstanceId) {
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		for (IdentityLink node : processEngine.getRuntimeService()
				.getIdentityLinksForProcessInstance(processInstanceId)) {
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("USERID", node.getUserId());
			map.put("ID", node.getUserId());
			map.put("TASKID", node.getTaskId());
			map.put("TYPE", node.getType());
			map.put("GROUPID", node.getGroupId());
			list.add(map);
		}
		return DataResult.getInstance(list, list.size(), 1, 100);
	}

	@Override
	public void setProcessInstanceVariable(String processInId, String key,
			String value) {
		processEngine.getRuntimeService().setVariable(processInId, key, value);

	}

	@Override
	public void activateProcessInstanceById(String processInstanceId) {
		processEngine.getRuntimeService().activateProcessInstanceById(
				processInstanceId);
	}

	@Override
	public void suspendProcessInstanceById(String processInstanceId) {
		processEngine.getRuntimeService().suspendProcessInstanceById(
				processInstanceId);
	}

	@Override
	public ProcessInstance getProcessInstance(String processInstanceId) {
		return processEngine.getRuntimeService().createProcessInstanceQuery()
				.processInstanceId(processInstanceId).singleResult();
	}

	@Override
	public DataResult queryUserCurrentTask(LoginUser currentUser,
			List<String> rolelist) {
		List<Map<String, Object>> returnList = new ArrayList<Map<String, Object>>();
		List<String> roles = new ArrayList<String>();
		for (String node : rolelist) {
			roles.add(node);
		}
		// 获得用户受理任务
		List<Task> tasks = processEngine.getTaskService().createTaskQuery()
				.taskAssignee(currentUser.getId()).orderByTaskCreateTime()
				.desc().listPage(0, 100);
		// taskName条件查询
		DBRule taskNameRule = null;
		for (Task task : tasks) {
			ProcessInstance pi = processEngine.getRuntimeService()
					.createProcessInstanceQuery().processInstanceId(
							task.getProcessInstanceId()).singleResult();
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("NAME", task.getName());
			map.put("USERID", task.getAssignee());
			map.put("CTIME", task.getCreateTime());
			map.put("PROINSID", task.getExecutionId());
			map.put("FORMKEY", task.getFormKey());
			map.put("ID", task.getId());
			map.put("PARENTTASKID", task.getParentTaskId());
			map.put("PRONAME", pi.getProcessDefinitionName());
			map.put("PROKEY", pi.getProcessDefinitionKey());
			// 构建主题信息
			map.put("TITLE", initProcessTitleDescription(task
					.getProcessInstanceId(), task.getProcessDefinitionId()));
			if (taskNameRule != null) {
				// taskName条件查询
				if (task.getName().indexOf(taskNameRule.getValue()) < 0) {
					continue;
				}
			}
			returnList.add(map);
		}
		DataResult result = DataResult.getInstance(returnList, returnList
				.size(), 1, returnList.size());
		return result;
	}

	@Override
	public DataResult queryUserJoinTask(LoginUser currentUser) {
		List<Map<String, Object>> returnList = new ArrayList<Map<String, Object>>();
		// 获得用户参与过的任务
		List<ProcessInstance> instances = processEngine.getRuntimeService()
				.createProcessInstanceQuery().involvedUser(currentUser.getId())
				.listPage(0, 100);
		for (ProcessInstance instance : instances) {
			Task task = processEngine.getTaskService().createTaskQuery()
					.processInstanceId(instance.getId()).singleResult();
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("NAME", instance.getProcessDefinitionName());
			map.put("ID", instance.getId());
			map.put("CTIME", task.getCreateTime());
			map.put("TASKNAME", task.getName());
			// 构建主题信息
			map.put("TITLE", initProcessTitleDescription(instance.getId(),
					instance.getProcessDefinitionId()));
			returnList.add(map);
		}
		DataResult result = DataResult.getInstance(returnList, returnList
				.size(), 1, returnList.size());
		return result;
	}

	@Override
	public DataResult queryUserWaitingTask(LoginUser currentUser,
			List<String> roleList) {
		List<Map<String, Object>> returnList = new ArrayList<Map<String, Object>>();
		List<String> roles = new ArrayList<String>();
		for (String node : roleList) {
			roles.add(node);
		}
		// 获得角色的待办任务
		List<Task> tasks = processEngine.getTaskService().createTaskQuery()
				.taskCandidateGroupIn(roles).orderByTaskCreateTime().asc()
				.listPage(0, 50);
		// 获得用户的待办任务
		tasks.addAll(processEngine.getTaskService().createTaskQuery()
				.taskCandidateUser(currentUser.getId()).listPage(0, 50));
		for (Task task : tasks) {
			ProcessInstance pi = processEngine.getRuntimeService()
					.createProcessInstanceQuery().processInstanceId(
							task.getProcessInstanceId()).singleResult();
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("NAME", task.getName());
			map.put("USERID", task.getAssignee());
			map.put("CTIME", task.getCreateTime());
			map.put("PROINSID", task.getExecutionId());
			map.put("FORMKEY", task.getFormKey());
			map.put("ID", task.getId());
			map.put("PARENTTASKID", task.getParentTaskId());
			map.put("PRONAME", pi.getProcessDefinitionName());
			map.put("PROKEY", pi.getProcessDefinitionKey());
			// 构建主题信息
			map.put("TITLE", initProcessTitleDescription(task
					.getProcessInstanceId(), task.getProcessDefinitionId()));
			returnList.add(map);
		}
		DataResult result = DataResult.getInstance(returnList, returnList
				.size(), 1, returnList.size());
		return result;
	}

	/**
	 * 构建流程实例的主题信息
	 * 
	 * @param processInstanceId
	 * @param processDefinitionId
	 * @return
	 */
	private String initProcessTitleDescription(String processInstanceId,
			String processDefinitionId) {
		String title = getProcessDefinition(processDefinitionId)
				.getDescription();
		if (title != null) {
			for (Entry<String, Object> val : processEngine.getRuntimeService()
					.getVariables(processInstanceId).entrySet()) {
				if (val.getValue() != null) {
					title = title.replaceAll("\\$\\{" + val.getKey() + "\\}",
							val.getValue().toString());
				}
			}
		}
		return title;
	}

	@Override
	public void startProcessDef(String processDefId, LoginUser currentUser,
			List<String> roles) {
		synchronized ("startProcessDef") {
			try {
				processEngine.getIdentityService().setAuthenticatedUserId(
						currentUser.getId());
				processEngine.getRuntimeService().startProcessInstanceById(
						processDefId,
						VariableProvider.getProcessStartVariable(currentUser,
								roles));
			} finally {
				processEngine.getIdentityService().setAuthenticatedUserId(null);
			}
		}
	}

	@Override
	public void saveTaskFormData(String taskId, Map<String, String> data) {
		if (data != null) {
			processEngine.getFormService().saveFormData(taskId, data);
		}
		TaskFormData taskform = processEngine.getFormService().getTaskFormData(
				taskId);
		formParser.saveHandle(taskform);
	}

	@Override
	public void submitTask(String taskId) {
		processEngine.getTaskService().complete(taskId);
	}

	@Override
	public Map<String, List<Map<String, Object>>> getUserStartableProcessDef(
			LoginUser currentUser, List<String> rolelist)
			throws SQLException {

		// 查找当前用户可以启动的流程定义
		DataQuery query = DataQuery
				.getInstance(
						"1",
						"b.CATEGORY_ AS TYPE,b.NAME_ AS NAME,b.ID_ AS id,b.VERSION_ AS VERSION ",
						"act_ru_identitylink a LEFT JOIN act_re_procdef b ON a.PROC_DEF_ID_=b.ID_");
		query.setPagesize(50);
		String roles = null;
		for (String node : rolelist) {
			if (roles == null) {
				roles = "'" + node + "'";
			} else {
				roles = roles + ",'" + node + "'";
			}
		}
		query.addRule(new DBRule("b.SUSPENSION_STATE_", "1", "="));
		if (roles == null) {
			query.addRule(new DBRule("a.USER_ID_", currentUser.getId(), "="));
		} else {
			query.addSqlRule(" and (a.GROUP_ID_ IN (" + roles
					+ ") OR a.USER_ID_='" + currentUser.getId() + "') ");
		}
		query.setDistinct(true);
		List<Map<String, Object>> list = null;
		list = query.search().getResultList();
		Map<String, List<Map<String, Object>>> prodefs = new HashMap<String, List<Map<String, Object>>>();
		for (Map<String, Object> node : list) {
			List<Map<String, Object>> nodeList = prodefs.get(node.get("TYPE")
					.toString());
			if (nodeList == null) {
				nodeList = new ArrayList<Map<String, Object>>();
				prodefs.put(node.get("TYPE").toString(), nodeList);
			}
			nodeList.add(node);
		}
		return prodefs;
	}

	@Override
	public Form getTaskForm(String taskId) {
		Map<String, Object> variables = processEngine
				.getRuntimeService()
				.getVariables(
						processEngine.getTaskService().createTaskQuery()
								.taskId(taskId).singleResult().getExecutionId());
		TaskFormData taskform = processEngine.getFormService().getTaskFormData(
				taskId);
		return formParser.getForm(taskform, variables);
	}

	@Override
	public void editProcessDefInfo(String processDefId, String flowType,
			String titleDes) {
		for (ProcessDefinition pro : processEngine.getRepositoryService()
				.createProcessDefinitionQuery().processDefinitionId(
						processDefId).list()) {
			processEngine.getRepositoryService().setProcessDefinitionCategory(
					pro.getId(), flowType);
		}
		farmBpmDao.editProcessDefTitleDescription(processDefId, titleDes);
	}

	@Override
	public ProcessDefinition getProcessDefinition(String processDefId) {
		return processEngine.getRepositoryService()
				.createProcessDefinitionQuery().processDefinitionId(
						processDefId).singleResult();
	}

	@Override
	public void claimTask(String taskid, LoginUser currentUser) {
		processEngine.getTaskService().claim(taskid, currentUser.getId());
	}

	@Override
	public Task getTask(String taskid) {
		return processEngine.getTaskService().createTaskQuery().taskId(taskid)
				.singleResult();
	}

	@Override
	public DataResult queryTaskIdentityLinks(DataQuery query, String taskId) {
		List<IdentityLink> list = processEngine.getTaskService()
				.getIdentityLinksForTask(taskId);
		List<Map<String, Object>> identityLinkslist = new ArrayList<Map<String, Object>>();
		for (IdentityLink node : list) {
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("USERID", node.getUserId());
			map.put("ID", node.getUserId());
			map.put("TASKID", node.getTaskId());
			map.put("TYPE", node.getType());
			map.put("GROUPID", node.getGroupId());
			identityLinkslist.add(map);
		}
		return DataResult.getInstance(identityLinkslist, identityLinkslist
				.size(), 1, 100);
	}

	@Override
	public void unclaimTask(String taskid) {
		processEngine.getTaskService().unclaim(taskid);
	}

	@Override
	public void setAssignee(String taskId, String userId) {
		processEngine.getTaskService().setAssignee(taskId, userId);
		// delegateTask(String taskId, String userId)//代表
		// setAssignee(String taskId, String userId)//受托人；分配到任务的人
		// setOwner(String taskId, String userId)//n. [经] 所有者；物主
	}

}
